package com.example.minesweepers;

import interfaces.Minesweepable;
import minesweeper.DynamicMinesweeper;
import android.app.Activity;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

public class MinesweeperController implements OnCheckedChangeListener,OnClickListener,OnLongClickListener {
	private Activity context;
	private int sizeRows;
	private int sizeCols;
	private Minesweepable minesweeper;
	private MinesweeperView minesweeperView;
	
	private void setupControllerListeners() {
		ToggleButton toggleButtonListenerSetuper;
		for(int i = 0; i < sizeCols * sizeRows; i++) {
			toggleButtonListenerSetuper = (ToggleButton) context.findViewById(i);
			toggleButtonListenerSetuper.setOnCheckedChangeListener(this);
			toggleButtonListenerSetuper.setOnLongClickListener(this);
		}
		
		Button smileFace = (Button) context.findViewById(sizeCols * sizeRows + 1);
		smileFace.setOnClickListener(this);
	}
	
	public void startNewGame() {
		minesweeper = null;
		minesweeperView = new MinesweeperView(context);
		minesweeperView.initializeViews(sizeRows, sizeCols);
		setupControllerListeners();
	}

	public MinesweeperController(Activity context, int sizeRows, int sizeCols) {
		this.context = context;
		this.sizeCols = sizeCols;
		this.sizeRows = sizeRows;
	}
	
	private void setupMinesweeper(int sizeWidth, int sizeHeight, int positionRow, int positionCol) {
		minesweeper = DynamicMinesweeper.createMinesweeperData(sizeWidth, sizeHeight, positionRow, positionCol);
		
		for (int j = 0; j < sizeRows; j++) {
			for (int i = 0; i < sizeCols; i++) {
				ToggleButton singleSquare = (ToggleButton) context.findViewById(i + sizeCols * j);
				if(minesweeper != null)
					setGameToggleButtonNumbers(minesweeper.getSquare(j, i), singleSquare);
			}
		}
		
		TextView mine = (TextView) context.findViewById(sizeRows * sizeCols + 3);
		mine.setText(minesweeperCustomStringUpdate());
		startChronometer();
	}

	private void startChronometer() {
		minesweeperView.getChronometer().start();
		minesweeperView.getChronometer().setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
			
			@Override
			public void onChronometerTick(Chronometer chronometer) {
				TextView chronometerTimeTextView = (TextView) context.findViewById(sizeCols * sizeRows + 2);
				if(chronometerTimeTextView.equals("999")) {
					chronometer.stop();
				}
				else {
					String timeString = Integer.toString((Integer.parseInt(chronometerTimeTextView.getText().toString()) + 1));

					while(timeString.length() < 3)
						timeString = "0" + timeString;
					
					chronometerTimeTextView.setText(timeString);
				}
			}
		});
	}
	
	private void setGameToggleButtonNumbers(int number, ToggleButton singleSquare) {
		if(number == -1) {
			//if there is a mine
			singleSquare.setBackgroundResource(R.drawable.mined_toggle_block);
		}
		else {
			singleSquare.setBackgroundResource(R.drawable.toggle_block);
		}
		if(number > 0){
			NumbersColourFactory.setApropriateColor(singleSquare, number);
			singleSquare.setTextOn("" + number);
		}
	}
	
	private String minesweeperCustomStringUpdate() {
		String minesString;
		if(minesweeper != null)
			minesString = Integer.toString(this.minesweeper.getNumberOfFlagsLeft());
		else 
			minesString = "";

		while(minesString.length() < 3)
			minesString = "0" + minesString;
		return minesString;
	}

	@Override
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
			if (buttonView.getId() < sizeCols * sizeRows) {
			//playing the actual game
			ToggleButton flagging = (ToggleButton) context.findViewById(sizeCols * sizeRows + 4);
			
			startupMinesweeperOnButton(buttonView, flagging);
			
			if (flagging.isChecked() && this.minesweeper != null) {

				makeChangesOnCheckedFlag(buttonView);
				
				TextView mine = (TextView) context.findViewById(sizeRows * sizeCols + 3);
				mine.setText(minesweeperCustomStringUpdate());
				
			} else if (!this.minesweeper.isFlagged(buttonView.getId() / sizeCols, buttonView.getId() % sizeCols) && isChecked) {
				buttonView.setEnabled(false);
				
				makeChangesOnUncheckedFlag(buttonView);
			}
		}
	}

	private void makeChangesOnUncheckedFlag(CompoundButton buttonView) {
		if (checkClickedSquare(buttonView.getId(), -1))
			gameOverToast("Game Over...\nYou Lost!", true);
		else {
			openSquare(buttonView.getId());
		}

		isGameWon();
	}

	private void makeChangesOnCheckedFlag(CompoundButton buttonView) {
		if(minesweeper.isFlagged(buttonView.getId() / sizeCols, buttonView.getId() % sizeCols) && this.minesweeper.getNumberOfFlagsLeft() >= 0) {
			//unflag it
			if(minesweeper.changeFlagSquareState(buttonView.getId() / sizeCols, buttonView.getId() % sizeCols)) {
				buttonView.setBackground(null);
				if(minesweeper != null)
					setGameToggleButtonNumbers(minesweeper.getSquare(buttonView.getId() / sizeCols, buttonView.getId() % sizeCols), (ToggleButton) buttonView);
				buttonView.setChecked(false);
			}
		}
		else if(this.minesweeper.getNumberOfFlagsLeft() != 0) {
			//flag it
			minesweeper.changeFlagSquareState(buttonView.getId() / sizeCols, buttonView.getId() % sizeCols);
			buttonView.setBackground(null);
			buttonView.setBackgroundResource(R.drawable.flagged_block);
			buttonView.setChecked(true);
			((ToggleButton) buttonView).setTextOn("");
			buttonView.setText("");
		}
		else {
			buttonView.setChecked(false);
		}
		
		isGameWon();
	}

	private void isGameWon() {
		if (this.minesweeper != null && this.minesweeper.isGameWon()) {
			// save game
			GameFaceButton face = (GameFaceButton) context.findViewById(sizeRows * sizeCols + 1);
			face.setBackgroundResource(R.drawable.happy_face);
			gameOverToast("Game Over...\nYou WON! :)", false);
		}
	}

	private void startupMinesweeperOnButton(CompoundButton buttonView,
			ToggleButton flagging) {
		if(minesweeper == null) {
			setupMinesweeper(sizeRows, sizeCols, buttonView.getId() / sizeCols, buttonView.getId() % sizeCols);
			flagging.setChecked(false);
		}
	}
	
	private void openSquare(int buttonNumberId) {
		if(minesweeper != null) {
			minesweeper.openSquare(buttonNumberId / sizeCols, buttonNumberId % sizeCols);
			if(checkClickedSquare(buttonNumberId, 0)) 
				rippleView();
		}
	}

	private void rippleView() {
		for(int i = 0; i < sizeRows * sizeCols; i++) {
			if(this.minesweeper != null && this.minesweeper.isOpened(i / sizeCols, i % sizeCols)) {
				ToggleButton button = (ToggleButton) context.findViewById(i);
				button.setChecked(true);
				button.setEnabled(false);
			}
		}
	}

	private boolean checkClickedSquare(int buttonNumberId, int checkWith) {
		return minesweeper.getSquare(buttonNumberId / sizeCols, buttonNumberId % sizeCols) == checkWith;
	}
	
	/**
	 * Displays a toast to the screen
	 * @param text - Displays this text
	 * @param isChangedGameState - true if the game is win, false otherwise
	 */
	private void gameOverToast(String text, boolean isChangedGameState) {
		minesweeperView.getChronometer().stop();
		
		showEndgameToast(text);
		immobilizeAllButtons();
		if(isChangedGameState) {
			GameFaceButton face = (GameFaceButton) context.findViewById(sizeRows * sizeCols + 1);
			face.setBackgroundResource(R.drawable.mined_face);
		}
		else {
			((GameActivity) context).saveGame(minesweeperView.getTime());
		}
	}

	private void immobilizeAllButtons() {
		for(int i = 0; i < sizeCols * sizeRows; i++) {
			//animation? -> some day
			ToggleButton immobilizeButton = (ToggleButton) context.findViewById(i);
			immobilizeButton.setEnabled(false); // can be optimized
		}
	}

	private void showEndgameToast(String text) {
		Toast toast = Toast.makeText(context, text, Toast.LENGTH_LONG);
		toast.setGravity(Gravity.CENTER, 0, 0);
		toast.show();
	}

	@Override
	public boolean onLongClick(View v) {
		if (v.getId() < sizeCols * sizeRows && this.minesweeper != null) {
			makeChangesOnCheckedFlag((CompoundButton) v);//->bug!

			TextView mine = (TextView) context.findViewById(sizeRows * sizeCols + 3);
			mine.setText(minesweeperCustomStringUpdate());
		}
		return true;
	}

	@Override
	public void onClick(View v) {
		startNewGame();
	}

}